<?php
/***************************************************************************
#                       PDO数据库操作类
# 封装数据库的 增 删 改 查
# 构造函数 => 接受参数设置($host,$user,$pwd,$dbName)以及
#             配置文件: HOST USERNAME PASSWORD DBNAME
#       说明: 如果配置文件正确或参数传输正确，则初始化对象成功则连入数据库
#    		  初始化对象但是参数有误，则可以用connect($host,$user,$pwd)重连
# 公共方法介绍 ： 
#   数据库的重连:                      connect($host,$user,$pwd)   
#   返回数据库链接资源：               get_handle()
#   切换数据库并选择返回字符集；       change_db ($dbName,$charset='')
#   发送Query查询:                     auery ($sql)
#
#   增 (通过关联数组插入数据)          arrInsert($tableName,$Arr)
#	删 (通过关联数组确定where条件)     arrDel($tableName,$Arr)
# 	改 (通过关联数组……)                arrUpdate ($tableName,$Newdat,$Wdat)
#   查 (返回二维关联数组)			   getAll($sql)
#   
# 	
#
***************************************************************************/
// require 'db.class.php';
require 'Log.class.php';

class pdoMysql {
	public static $config = array();   // 设置连接参数
	public static $pdo = NULL;		   // POD 保存对象
	public static $PDOStatement=null;  // 保存PDOStatement对象
	
	# 单列模式
	protected static $ins =  null;     // 保存pdoMysql 对象

	final protected function __construct(){
		// 读取配置文件
		defined('DB_HOST')     ? self::$config['db_host']  = DB_HOST     :0;
		defined('DB_CHAR')     ? self::$config['charset']  = DB_CHAR     :0;
		defined('DB_USERNAME') ? self::$config['db_user']  = DB_USERNAME :0;
		defined('DB_PASSWORD') ? self::$config['db_pass']  = DB_PASSWORD :0;
		defined('DB_NAME')     ? self::$config['db_name']  = DB_NAME     :0;
		defined('DB_TYPE')     ? self::$config['db_type']  = DB_TYPE     :0;

		// 链接数据库
		self::connect(self::$config);

	}

	public static function init($dbConfig=''){
		// 读取构造参数
		if (is_array($dbConfig)) {
			// 逐一判断
			if (array_key_exists('db_host',$dbConfig)) self::$config['db_host'] = $dbConfig['db_host'];
			if (array_key_exists('db_user',$dbConfig)) self::$config['db_user'] = $dbConfig['db_user'];
			if (array_key_exists('db_pass',$dbConfig)) self::$config['db_pass'] = $dbConfig['db_pass'];
			if (array_key_exists('db_name',$dbConfig)) self::$config['db_name'] = $dbConfig['db_name'];
			if (array_key_exists('db_type',$dbConfig)) self::$config['db_type'] = $dbConfig['db_type'];
			if (array_key_exists('charset',$dbConfig)) self::$config['charset'] = $dbConfig['charset'];

		}

		// 单列构造
		if (self::$ins instanceof self) {
			return self::$ins;
		}else{
			self::$ins = new self();
			return self::$ins;
		}
	}
	// 防止克隆对象
	final protected function __clone(){
		return false;
	}

	// 数据库连接/数据库重连
	public static function connect($dbConfig= ''){
		if (is_array($dbConfig)) {
			// 逐一判断
			if (array_key_exists('db_host',$dbConfig)) self::$config['db_host'] = $dbConfig['db_host'];
			if (array_key_exists('db_user',$dbConfig)) self::$config['db_user'] = $dbConfig['db_user'];
			if (array_key_exists('db_pass',$dbConfig)) self::$config['db_pass'] = $dbConfig['db_pass'];
			if (array_key_exists('db_name',$dbConfig)) self::$config['db_name'] = $dbConfig['db_name'];
			if (array_key_exists('db_type',$dbConfig)) self::$config['db_type'] = $dbConfig['db_type'];
			if (array_key_exists('charset',$dbConfig)) self::$config['charset'] = $dbConfig['charset'];

		}	
		
		// 判断是否支持PDO对象
		if(!class_exists("PDO")) {
 			$errStr = 'can not support PDO ,pleass loading PDO';
			echo $errStr;
			// 如果存在日志类，则写入日志
			if (class_exists("Log")) Log::write($errStr);
		}
		# 链接数据库
		$dsn = 'mysql:host='.self::$config['db_host'];
		if (isset(self::$config['db_name'])) 
			$dsn .= ';dbname='.self::$config['db_name'];
		
		try{
			$oTemp = new PDO($dsn,self::$config['db_user'],self::$config['db_pass'] );
		}catch(PDOException $e){
			echo $e->getMessage();
			// 如果存在日志类 记录异常日志
			if (class_exists("Log")) Log::write($e->getMessage());
		}
		if (isset($oTemp) && ($oTemp != false)) {
			self::$pdo = $oTemp;
		}

	}
	// 发送sql指令
	public function  exec($sql){
		$stmt = self::$pdo->exec($sql);
		// 如果存在日志类 记录sql语句
		if (class_exists("Log")) Log::write($sql);
		return $stmt;
	}

	// 发送Query 查询
	public function query ($sql){
		self::$PDOStatement = self::$pdo->prepare($sql);
		// 如果存在日志类 记录sql语句
		if (class_exists("Log")) Log::write($sql);
		$res = self::$PDOStatement->execute();
		return $res;
	}
	
	// 选择（切换）数据库
	public function change_db ($dbName,$charset=''){
		if ($dbName != '')  self::$config['db_name'] = $dbName;
		if ($charset != '') self::$config['charset'] = $charset;	
		// 选择数据库
		$sql = 'USE '.self::$config['db_name'] ;
		$this->exec($sql);
		// 设置字符集
		$sql = 'SET NAMES '.self::$config['charset'];
		$this->exec($sql);
	}

	private function Iinto ($tableName,$Arr){
		$insert_sql = 'INSERT INTO '.$tableName.'(';
		foreach ($Arr as $name => $value ) $insert_sql .= $name .',';
		// 去除最后一个字符
		$insert_sql = substr($insert_sql, 0,-1);
		$insert_sql .= ') values(';
		foreach ($Arr as $name => $value ){
			if (is_string($value)) $insert_sql .= '"'.$value . '"' .',';
			else				   $insert_sql .=     $value .',';
		}
		// 去除最后一个字符
		$insert_sql = substr($insert_sql, 0,-1);
		$insert_sql .= ');';
		
		return $this->exec($insert_sql);
	}

	// 通过关联数组插入数据
	public function arrInsert ($tableName,$Arr){
		// 判断$Arr 是否二维数组
		if(is_array($Arr)){
			foreach ($Arr as $k => $v) {
				if (is_array($Arr[$k])) {
					$Is2=2;
					break;
				} 
				else{ 
					$Is2 = 1;
					break ;
				}
			}
		}else $Is2 = 0;

		if (2==$Is2) {
			foreach ($Arr as $key => $value)
				$this->Iinto($tableName,$Arr[$key])? $isOk=true :$isOk=false;	
		}
		else if (1==$Is2)	$this->Iinto($tableName,$Arr)?$isOk=true :$isOk=false;
		else if (0==$Is2)   $isOk = false;

		return $isOk;
	}


	// 通过关联数组 删除数据
	public function arrDel($tableName,$Arr){
		// 如果数组为空 则为非法输入
		if (empty($Arr)) {
			return false;
		}
		$delsql = 'DELETE FROM '.$tableName.' WHERE ';
		foreach ($Arr as $key => $value) {
			// 如果数组并非索引数组 既为非法输入
			if (!is_string($key)) return false;
			if (is_string($value)) $delsql .= $key.'="'.$value.'"';  
			else 				   $delsql .= $key.'=' .$value;
			$delsql .= ' AND ';
		}
		$delsql = substr($delsql, 0, -5);
		return $this->exec($delsql);
	}
	
	// 通过两个关联数组 修改数据
	public function arrUpdate ($tableName,$Newdat,$Wdat){
		# "UPDATE tablees SET  WHERE "
		// 如果数组为空 则为非法输入
		if (empty($Wdat)) {
			return false;
		}
		$Csql= 'UPDATE '.$tableName.' SET ';

		foreach ($Newdat as $key => $value) {
			if (is_string($value)) $Csql .= $key.'="'.$value.'"';  
			else 				   $Csql .= $key.'=' .$value;
			$Csql .=',';
		}
		$Csql = substr($Csql, 0,-1);
		$Csql .= ' WHERE ';
		
		foreach ($Wdat as $k => $v) {
			if (!is_string($key)) return false;    #防止(where 1)修改所有数据
			if (is_string($value)) $Csql .= $k.'="'.$v.'"';  
			else 				   $Csql .= $k.'=' .$v;
			$Csql .=' AND ';
		}
		$Csql = substr($Csql, 0,-5);
		return $this->exec($Csql);

	}

	// 查询返回关联数组
	public function getAll($sql){
		$res = $this->query($sql);
		$arr = self::$PDOStatement->fetchAll(PDO::FETCH_ASSOC);
		return $arr;
	}
	
	// 返回单个值
	public function getOne($sql){
		$res = $this->query($sql);
		$one = self::$PDOStatement->fetch();
		return $one[0];
	}
	
	// 查询数据库中数据的条数
	public function getCount($tableName,$arrDat=''){
		$sql = 'SELECT COUNT(*) FROM '.$tableName.' WHERE ';
		if (!$arrDat == ''){
			foreach ($arrDat as $key => $value) {
			// 如果数组并非索引数组 既为非法输入
				if (!is_string($key)) return false;
				if (is_string($value)) $sql .= $key.'="'.$value.'"';  
				else 				   $sql .= $key.'=' .$value;
				$sql .= ' AND ';
			}
			$sql = substr($sql, 0, -5);
		}else{
			$sql .='1';
		}
		
		return $this->getOne($sql);
	}

}